﻿/*****************************************************************************
 * Qwt Examples - Copyright (C) 2002 Uwe Rathmann
 * This file may be used under the terms of the 3-clause BSD License
 *****************************************************************************/

#include "CurveTracker.h"

#include <QwtPickerMachine>
#include <QwtPlot>
#include <QwtPlotCurve>
#include <QwtText>

#include <QPen>

struct compareX
{
    inline bool operator()(const double x, const QPointF& pos) const
    {
        return (x < pos.x());
    }
};

CurveTracker::CurveTracker(QWidget* canvas) : QwtPlotPicker(canvas)
{
    setTrackerMode(QwtPlotPicker::ActiveOnly);
    setRubberBand(VLineRubberBand);

    setStateMachine(new QwtPickerDragPointMachine());
}

QRect CurveTracker::trackerRect(const QFont& font) const
{
    QRect r = QwtPlotPicker::trackerRect(font);

    // align r to the first curve

    const QwtPlotItemList curves = plot()->itemList(QwtPlotItem::Rtti_PlotCurve);
    if (curves.size() > 0) {
        QPointF pos = invTransform(trackerPosition());

        const QLineF line = curveLineAt(static_cast< const QwtPlotCurve* >(curves[ 0 ]), pos.x());
        if (!line.isNull()) {
            const double curveY = line.pointAt((pos.x() - line.p1().x()) / line.dx()).y();

            pos.setY(curveY);
            pos = transform(pos);

            r.moveBottom(pos.y());
        }
    }

    return r;
}

QwtText CurveTracker::trackerTextF(const QPointF& pos) const
{
    QwtText trackerText;

    trackerText.setColor(Qt::black);

    QColor c("#333333");
    trackerText.setBorderPen(QPen(c, 2));
    c.setAlpha(200);
    trackerText.setBackgroundBrush(c);

    QString info;

    const QwtPlotItemList curves = plot()->itemList(QwtPlotItem::Rtti_PlotCurve);

    for (int i = 0; i < curves.size(); i++) {
        const QString curveInfo = curveInfoAt(static_cast< const QwtPlotCurve* >(curves[ i ]), pos);

        if (!curveInfo.isEmpty()) {
            if (!info.isEmpty())
                info += "<br>";

            info += curveInfo;
        }
    }

    trackerText.setText(info);
    return trackerText;
}

QString CurveTracker::curveInfoAt(const QwtPlotCurve* curve, const QPointF& pos) const
{
    const QLineF line = curveLineAt(curve, pos.x());
    if (line.isNull())
        return QString();

    const double y = line.pointAt((pos.x() - line.p1().x()) / line.dx()).y();

    QString info("<font color="
                 "%1"
                 ">%2</font>");
    return info.arg(curve->pen().color().name()).arg(y);
}

QLineF CurveTracker::curveLineAt(const QwtPlotCurve* curve, double x) const
{
    QLineF line;

    if (curve->dataSize() >= 2) {
        const QRectF br = curve->boundingRect();
        if ((br.width() > 0) && (x >= br.left()) && (x <= br.right())) {
            size_t index = qwtUpperSampleIndex< QPointF >(*curve->data(), x, compareX());

            if (index == curve->dataSize() && x == curve->sample(curve->dataSize() - 1).x()) {
                // the last sample is excluded from qwtUpperSampleIndex
                index = curve->dataSize() - 1;
            }

            if (index > 0) {
                line.setP1(curve->sample(index - 1));
                line.setP2(curve->sample(index));
            }
        }
    }

    return line;
}
